package cn.ztydata.teachingsystem.heaven.service;

import cn.ztydata.teachingsystem.common.Page;
import cn.ztydata.teachingsystem.exception.ServiceException;
import cn.ztydata.teachingsystem.heaven.cons.Constants;
import cn.ztydata.teachingsystem.heaven.cons.Roles;
import cn.ztydata.teachingsystem.heaven.dao.*;
import cn.ztydata.teachingsystem.heaven.entity.Department;
import cn.ztydata.teachingsystem.heaven.entity.DeptStatistics;
import cn.ztydata.teachingsystem.heaven.entity.Role;
import cn.ztydata.teachingsystem.heaven.exception.ExcelException;
import cn.ztydata.teachingsystem.util.ExcelUtil;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.InputStream;
import java.util.*;

/**
 * 系部服务类
 *
 * @author fanruiping
 * @since 2014-11-29
 */
@Service
public class DepartmentService extends BaseService {
    @Autowired
    private DepartmentDao departmentDao;
    @Autowired
    private ResourceDao resourceDao;
    @Autowired
    private RoleDao roleDao;
    @Autowired
    private SpecialtyService specialtyService;
    @Autowired
    private CourseService courseService;
    @Autowired
    private ResourceService resourceService;
    @Autowired
    private SpecialtyDao specialtyDao;
    @Autowired
    private CourseDao courseDao;

    /**
     * 获取系部列表数据
      * @param pageNum 页码
     * @param pageSize 每页显示条数
     * @return Page
     *
     * @author fanruiping
     * @since 2014-11-29
     */
    public Page<Department> getList(int pageNum, int pageSize){
        log.debug("return department list");

        return departmentDao.getList(pageNum, pageSize);
    }

    /**
     * 获取系部详细信息
     * @param id 编号
     * @return Department
     *
     * @author fanruiping
     * @since 2014-11-29
     */
    public Department getDetail(long id){
        log.debug("return department detail by id");

        return departmentDao.getById(id);
    }

    /**
     * 根据系部编码获取系部详细
     * @param number 系部编码
     * @return Department
     *
     * @author fanruiping
     * @since 2014-12-01
     */
    public Department getDetailByNumber(String number){
        log.debug("return department detail by deptNum");

        return departmentDao.getByNumber(number);
    }

    /**
     * 根据系部编码和编号获取系部详细
     * @param number 编码
     * @param id 编号
     * @return Department
     *
     * @author fanruiping
     * @since 2014-12-01
     */
    public Department getDetailByNumberAndId(String number, long id){
        log.debug("return department detail by number and id");

        return departmentDao.getByNumberAndId(number, id);
    }

    /**
     * 新增系部
     * @param entity 实体类
     *
     * @author fanruiping
     * @since 2014-11-29
     */
    public void add(Department entity){
        departmentDao.add(entity);
    }

    /**
     * 更新系部数据
     * @param entity 实体类
     *
     * @author fanruiping
     * @since 2014-11-29
     */
    public void modify(Department entity){
        //更新课程所属系部名称
        if(-1 == courseDao.updateDeptName(entity.getId(),entity.getName())){
            log.debug("update course deptName fail");

            log.warn("更新课程所属系部名称失败");

            throw new ServiceException("更新课程所属系部名称失败");
        }

        if(!departmentDao.modify(entity)){
            log.debug("update department info fail");

            log.error("更新系部信息失败");

            throw new ServiceException("更新系部信息失败");
        }
    }

/**
     * 删除指定系部
     * @param id 编号
     *
     * @author fanruiping
     * @since 2014-11-29
     */
    public int delete(long id){
        log.debug("删除指定系部");

        return departmentDao.delete(id);
    }

    /**
     * 获取所有系部数据
     * @return List
     *
     * @author fanruiping
     * @since 2014-12-02
     */
    public List<Department> getAll(){
        log.debug("return department list");

        return departmentDao.getAll();
    }

    /**
     * 读取Excel文件
     * @param in 文件输入流
     *
     * @author chenxin
     * @since 2014/11/29
     */
    public List<Department> readFromExcel(InputStream in) {
        //定义标题-属性的映射
        LinkedHashMap<String, String> fieldMap = Maps.newLinkedHashMap();
        fieldMap.put("系部名称", "name");
        fieldMap.put("系部编码", "number");
        fieldMap.put("系部简介", "intro");

        log.debug("Excel中系部记录转为List");
        return ExcelUtil.excelToList(in, Department.class, fieldMap);
    }

    /**
     * 批量新增系部
     * @param deptList 系部集合
     *
     * @author cx
     * @since 2014-11-29
     */
    @Transactional
    public void saveDepts(final List<Department> deptList) {
        try {
            //执行批量插入
            departmentDao.saveDepts(deptList);
        } catch(DataAccessException ex) {
            log.debug("导入系部-批量新增异常");

            log.warn("导入系部-批量新增异常", ex);
            throw new ExcelException();
        }
    }

    /**
     * 统计系部信息
     * @return List
     *
     * @author cx
     * @since 2014-12-01
     */
    @Cacheable(value = "teachingSystem:cache:count", key = "'dept'")
    public List<DeptStatistics> getStatisticsInfo() {
        //获取所有的系部信息
        List<DeptStatistics> deptInfoList = departmentDao.getAllForName();
        if (deptInfoList.isEmpty()) {
            log.debug("暂无系部信息:deptInfoList.isEmpty()");
            throw new ServiceException("暂无系部统计信息");
        }

        //获取系部的专业总数
        Map<String, Long> deptToSpecialty = specialtyService.getSpecTotalForDept();

        //获取系部的课程总数
        Map<Long, Long> deptToCourse = courseService.getCourseTotalForDept();

        //获取系部的资源总数
        Map<Long, Long> deptToRsc = resourceService.countForDept(null);

        //组合系部资源的统计信息
        log.debug("循环系部信息集合");
        for (DeptStatistics deptStatistics : deptInfoList) {
            //获取专业数量、课程数量、资源数量
            Long specialtyTotal = deptToSpecialty.get(deptStatistics.getNumber());
            Long courseTotal = deptToCourse.get(deptStatistics.getId());
            Long rscTotal = deptToRsc.get(deptStatistics.getId());

            deptStatistics.setSpecialtyTotal(specialtyTotal == null ? 0 : specialtyTotal);
            deptStatistics.setCourseTotal(courseTotal == null ? 0 : courseTotal);
            deptStatistics.setRscTotal(rscTotal == null ? 0 : rscTotal);
        }

        log.debug("return 系部统计信息集合");
        return deptInfoList;
    }

    /**
     * 检查导入系部数据中的编码冲突
     * @param deptList 系部集合
     *
     * @author cx
     * @since 2014-12-04
     */
    public void checkForNum(final List<Department> deptList) {
        if (deptList.size() > Constants.TOTAL_2K) {
            log.debug("导入数据量超过" + Constants.TOTAL_2K);
            throw new ExcelException("导入数据量超过" + Constants.TOTAL_2K);
        }

        //抽取系部的编码集合
        Set<String> deptNumSet = Sets.newHashSet();
        int index = 1;
        log.debug("循环校验导入系部数据的编码冲突");
        for (Department department : deptList) {
            if (department.getNumber() == null) {
                log.debug("导入了编码为空的系部:department.getNumber() == null");
                throw new ExcelException("导入数据中第" + index + "条数据系部编码为空");
            }

            //检查导入数据中是否存在重复编码
            if (deptNumSet.contains(department.getNumber())) {
                log.debug("导入系部数据中存在重复编码:deptNumSet.contains(department.getNumber())");
                throw new ExcelException("导入数据中第" + index + "条数据系部编码重复" );
            }

            deptNumSet.add(department.getNumber());
            index++;
        }

        //检查导入数据编码是否与数据库中记录冲突
        String duplicateNum = departmentDao.getDuplicateNum(deptNumSet);
        deptNumSet.clear();
        if (duplicateNum != null) {
            log.debug("导入系部数据与表记录冲突:duplicateNum != null");
            throw new ExcelException("编码为:" + duplicateNum + "的系部已经存在！");
        }
    }

    /**
     * 根据专业编号获取系部编号
     * @param specialtyId 专业编号
     * @return Long
     *
     * @author fanruiping
     * @since 2014-12-18
     */
    public Long getIdBySpecialtyId(Long specialtyId){
        log.debug("根据专业编号获取系部编号");
        return departmentDao.getIdBySpecId(specialtyId);
    }

    /**
     * 根据编号集合获取系部数据集合
     * @param ids 编号集合
     * @return List
     *
     * @author fanruiping
     * @since 2014-12-29
     */
    public List<Department> getByIds(Set<Long> ids){
        log.debug("根据编号集合获取系部集合");

        return departmentDao.getByIds(ids);
    }

    /**
     * 获取多个系部的map格式信息
     *
     * @author chenxin
     * @since 2015/1/12
     */
    public Map<Long, Department> getMapByIds(Set<Long> ids) {
        Map<Long, Department> result = Maps.newHashMap();

        if (ids == null || ids.isEmpty()) {
            return result;
        }

        //获取系部信息
        List<Department> departments = departmentDao.getByIds(ids);
        //转换为"系部ID->系部"格式
        for (Department department : departments) {
            result.put(department.getId(), department);
        }

        return result;
    }

    /**
     * 获取首页系部列表
     *
     * @author chenxin
     * @since 2015/1/10
     */
    @Cacheable(value = "teachingSystem:cache:index", key = "'depts:'.concat(#top)")
    public List<Department> getIndexList(final int top) {
        Map<Long, Long> deptRscMap = Maps.newHashMap();
        int tag = 0; //默认按照课程总量排序统计系部信息

        //按照课程总数排名统计系部信息
        List<Department> depts = courseDao.getTopTotalForDept(top);


        if (depts.isEmpty()) {
            log.debug("按照课程总数排名获取统计系部信息不为空：depts.isEmpty()");
            tag++; //按照资源总数排序统计系部信息
            depts = resourceDao.getTopTotalForDept(top);


            if (depts.isEmpty()) { //获取n个系部信息
                log.debug("获取n个系部信息:depts.isEmpty()");
                return departmentDao.getByLimit(top);
            }
        }

        //生成系部ID集合
        Set<Long> deptIds = Sets.newHashSet();
        log.debug("生成系部ID集合:for (Department dept : depts)");
        for (Department dept : depts) {
            deptIds.add(dept.getId());
        }
        if (tag == 0) {
            log.debug("默认按照课程总量排序统计系部信息为零：tag == 0");
            //获取指定系部的资源总数
            deptRscMap = resourceService.countForDept(deptIds);
        }

        //获取指定系部的基本信息
        Map<Long, Department> deptMap = getMapByIds(deptIds);

        //绑定系部的基本信息
        log.debug("绑定系部的基本信息:for (Department dept : depts)");
        for (Department dept : depts) {
            if (tag == 0) { //绑定系部的资源总数
                log.debug("绑定系部的资源总数为零：tag == 0");
                dept.setRscTotal(deptRscMap.get(dept.getId()));
            }

            dept.setName(deptMap.get(dept.getId()).getName());
            dept.setNumber(deptMap.get(dept.getId()).getNumber());
        }

        log.debug("获取首页系部列表");
        return depts;
    }

    /**
     * 获取系部管理员负责的系部列表
     * @param teacherId 教师编号
     * @return Set
     *
     * @author fanruiping
     * @since 2014-2-29
     */
    @Cacheable(value = "teachingSystem", key = "'authorize:getByLeader:'.concat(#teacherId)")
    public List<Department> getByLeader(Long teacherId){
        Set<Long> ids = roleDao.getByTeacherId(teacherId, Roles.DEPT_ADMIN);

        //系部编号集合为空
        if(ids.isEmpty()){
            return new ArrayList<>();
        }

        return departmentDao.getByIds(ids);
    }

    /**
     * 获取专业负责人负责专业的所属系部集合
     * @param teacherId 专业负责人编号
     * @return List
     *
     * @author fanruiping
     * @since 2015-05-13
     */
    public List<Department> getBySpecLeader(Long teacherId){
        List<String> deptNums = specialtyDao.getDeptNumByLeader(teacherId);

        //判断系部编码集合为空
        if(deptNums.isEmpty()){
            return new ArrayList<>();
        }

        return departmentDao.getByNumbers(deptNums);
    }
}
